import cn.hutool.core.collection.CollUtil;
import org.slf4j.Logger;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import pers.chao.cacheable.core.annotation.*;
import pers.chao.cacheable.core.consts.Division;
import pers.chao.cacheable.core.consts.EvictEqType;
import pers.chao.cacheable.core.consts.PushDirection;
import pers.chao.cacheable.infrastructure.utils.AopContextUtil;
import pers.chao.tool.infrastructure.log.BaseLogFactory;

import java.util.*;

/**
 * Description: 各种结构的缓存测试方法
 *
 * @author W.Chao
 * @date 2020/12/13 16:00
 **/
@RestController
// 使用我的另一个starter，用于日志打印，方便查看相关结果
//@AccessLog(module = "controller", description = "controller access log test")
public class Example {
	private static Logger logger = BaseLogFactory.getLogger(Example.class);

	@GetMapping("/hello")
	public String hello() {
		logger.info("ohhhhhhhhhhhhhhhhh!!!!!");
		return "hello";
	}

	// string类型测试
	@GetMapping("/value/{string}/{number}")
	@Cache(prefix = "Str", key = "#string+#number", separator = Division.COLON)
	@CacheValue
	public String string(@PathVariable String string, @PathVariable Integer number) {
		return "this is a STRING testing";
	}

	@GetMapping("/value/{string}/delete")
	@Cache(prefix = "Str", key = "#string", evict = true)
	@CacheValue
	public String stringDelete(@PathVariable String string) {
		return "string";
	}

	// bitmap测试
	@GetMapping("/bitmap/{pos}/{expire}")
	@Cache(prefix = "", key = "bitmap", expire = "#expire")
	@CacheBitmap(pos = "#pos")
	public Boolean bitmap(@PathVariable Integer pos, @PathVariable String expire) {
		return true;
	}

	@GetMapping("/bitmap/delete")
	@Cache(prefix = "", key = "bitmap", evict = true)
	@CacheBitmap(pos = "")
	public Boolean bitmapDelete() {
		return false;
	}

	// list测试
	@GetMapping("/list/{key}")
	@Cache(prefix = "list", key = "#key")
	@CacheList
	public List<Integer> list(@PathVariable String key) {
		return Arrays.asList(1, 2, 3, 4);
	}

	@GetMapping("/list/{key}/ddd")
	@Cache(prefix = "list", key = "#key", update = true)
	@CacheList(pushDirection = PushDirection.LEFT, replaceAll = true)
	public List<Integer> listEvict(@PathVariable String key) {
		return Arrays.asList(1, 2, 3, 4, 4, 4, 4, 4, 4);
	}

	@GetMapping("/list/{key}/string")
	@Cache(prefix = "list", key = "#key", update = true)
	@CacheList(pushDirection = PushDirection.LEFT, replaceAll = true)
	public List<Double> listEvictString(@PathVariable String key) {
		return Arrays.asList(4.4, 1.1, 1.0);
	}

	@GetMapping("/list/{key}/{eqValue}")
	@Cache(prefix = "list", key = "#key", update = true)
	@CacheList(pushDirection = PushDirection.LEFT, evictEq = "#eqValue", eqValueType = EvictEqType.INTEGER)
	public List<Integer> listEvict(@PathVariable String key, @PathVariable String eqValue) {
		return Arrays.asList(1, 2, 3, 1111);
	}

	@GetMapping("/list/{key}/delete")
	@Cache(prefix = "list", key = "#key", evict = true, update = true)
	@CacheList(pushDirection = PushDirection.LEFT)
	public List<Integer> listEvictDelete(@PathVariable String key) {
		return Arrays.asList(1, 2, 3, 4, 4, 4, 4, 4, 4);
	}

	@GetMapping("/list/{key}/trim")
	@Cache(prefix = "list", key = "#key", update = true)
	@CacheList(pushDirection = PushDirection.LEFT, trim = {0, 2})
	public List<Integer> listEvictTrim(@PathVariable String key) {
		return new LinkedList<>();
	}


	// set测试
	@GetMapping("/set/{key}")
	@Cache(prefix = "set", key = "#key")
	@CacheSet
	public Set<Integer> set(@PathVariable String key) {
		return CollUtil.newHashSet(1, 2, 3);
	}

	@GetMapping("/set/{key}/replace")
	@Cache(prefix = "set", key = "#key", update = true)
	@CacheSet(replaceAll = true)
	public Set<String> setReplaceAll(@PathVariable String key) {
		return CollUtil.newHashSet("1", "2");
	}

	@GetMapping("/set/{key}/{evict}")
	public Set<String> setEvict(@PathVariable String key, @PathVariable String evict) {
		/**
		 * 方法调用时会发生切面失效，解决方法如下
		 * @see {per.chao.cacheable.utils.AopContextUtil}
		 */
		AopContextUtil.getCurrentAopProxy(Example.class).setTypeTestAndAopProxyTest(key, CollUtil.newHashSet("1"));
		return CollUtil.newHashSet("string", "set");
	}

	//		@IgnoreLog
	@Cache(prefix = "set", key = "#key", update = true)
	@CacheSet(evictElement = "#set", eqValueType = EvictEqType.STRING)
	public void setTypeTestAndAopProxyTest(String key, Set<String> set) {

	}

	// zset测试
	@GetMapping("/zset/{key}")
	@Cache(prefix = "zset", key = "#key", update = true)
	@CacheZSet(replaceAll = true)
	public Map<String, Double> zset(@PathVariable String key) {
		Map<String, Double> map = new HashMap<>();
		map.put("m1", 1.0);
		map.put("m2", null);
		map.put("m3", 3.0);
		return map;
	}

	@GetMapping("/zset/{key}/{evict}")
	@Cache(prefix = "zset", key = "#key", update = true)
	@CacheZSet(evictElement = "#evict")
	public Map<String, Double> zsetEvict(@PathVariable String key, @PathVariable String evict) {
		Map<String, Double> map = new HashMap<>();
		map.put("m1", 1.0);
		map.put("m2", null);
		map.put("m3", 3.0);
		return map;
	}

	@GetMapping("/zset/{key}/aop")
	public Map<String, Double> zsetEvictAop(@PathVariable String key) {
		Map<String, Double> map = new HashMap<>();
		map.put("m3", 3.0);
		AopContextUtil.getCurrentAopProxy(Example.class).zsetTypeTestAndAopProxyTest(key, "m3");
		return map;
	}

	//		@IgnoreLog
	@Cache(prefix = "zset", key = "#key", update = true)
	@CacheZSet(evictElement = "#item", eqValueType = EvictEqType.STRING)
	public void zsetTypeTestAndAopProxyTest(String key, String item) {

	}

	// map测试
	@GetMapping("/map/{key}")
	@Cache(prefix = "map", key = "#key", update = true)
	@CacheMap
	public Map<String, Object> map(@PathVariable String key) {
		Map<String, Object> map = new HashMap<>();
		map.put("m1", 1.0);
		map.put("m2", 2.0);
		map.put("m3", 3.0);
		return map;
	}

	@GetMapping("/map/{key}/{evictItem}/evict")
	@Cache(prefix = "map", key = "#key", update = true)
	@CacheMap(evictItem = "#evictItem")
	public Map<String, Object> mapEvictItem(@PathVariable String key, @PathVariable String evictItem) {
		Map<String, Object> map = new HashMap<>();
		return map;
	}

	@GetMapping("/map/{key}/{updateItem}")
	@Cache(prefix = "map", key = "#key", update = true)
	@CacheMap(updateItem = "#updateItem")
	public Map<String, Object> mapUpdateItem(@PathVariable String key, @PathVariable String updateItem) {
		Map<String, Object> map = new HashMap<>();
		map.put("m2", 99);
		return map;
	}

	@GetMapping("/map/{key}/{updateItem}/2")
	@Cache(prefix = "map", key = "#key", update = true)
	@CacheMap(updateItem = "#updateItem")
	public Object mapUpdateItem2(@PathVariable String key, @PathVariable String updateItem) {
		return "go";
	}

	// 后面的部分数据结构没有测试expire、删除key等方法
	// 因为实现和string、bitmap等相同，故不测试
	// 主要测试了具体结构的特殊方法，例如list的push方向等
}
